#include <a_samp>

#define SLOTS 50
#define STANDARD_PLAYER_SKIN 15

#define COLOUR_SERVMESSAGE 0xFFFFCCFF
#define COLOUR_ADM 0x33CCFFAA
#define COLOUR_PLAYERACTION 0xB3FF66FF

forward SavePlayerFile(playerid);

main()
{
    print("                                    __       ");
	print("  _________  ____  ________  ____  / /_      ");
	print(" / ___/ __ \\/ __ \\/ ___/ _ \\/ __ \\/ __/  ");
	print("/ /__/ /_/ / / / / /__/  __/ /_/ / /_        ");
	print("\\___/\\____/_/ /_/\\___/\\___/ .___/\\__/   ");
	print("                         /_/                 ");
}
new sfpd[27], safr[10], san[5];

enum RankInfo
{
	rankname[64],
};

new OrgRankNames[1][9][RankInfo] =
{
	{ { "(none)" }, { "junior admin"}, { "senior admin"}, { "super admin"}, { "staff admin" }, { " "}, { " "}, { " "}, { " " } } // admin ranks
};

enum _accounts
{
	// data that's being saved
	aPassword[16],
	aSkin,
	aAdmin,
	
	// data not being saved
	bool: aLoggedIn,
	bool: aIsMuted,
	
	aSpectating,
};
new AccountInfo[SLOTS][_accounts];

public OnGameModeInit()
{
	// sa-mp settings
	SetNameTagDrawDistance(25.0);
	ShowNameTags(1);
	AllowInteriorWeapons(1);
	AllowAdminTeleport(0);
    EnableStuntBonusForAll(0);
    EnableZoneNames(0);
    EnableTirePopping(1);
    SetDisabledWeapons(10,11,12,13,15,26,28,32,35,36,37,38,39,40,43,44,45);
    DisableInteriorEnterExits();
    
    // SF-PD
	sfpd[0] = AddStaticVehicleEx (597,-1612.5692,732.6268,-5.4742,176.9741,0,1,900); 	// sfpd 1
	sfpd[1] = AddStaticVehicleEx (597,-1600.5076,692.8683,-5.4740,0.2970,0,1,900); 		// sfpd 2
	sfpd[2] = AddStaticVehicleEx (597,-1604.3767,692.6443,-5.4757,359.7142,0,1,900); 	// sfpd 3
	sfpd[3] = AddStaticVehicleEx (597,-1608.7444,692.8803,-5.4734,180.9627,0,1,900); 	// sfpd 4
	sfpd[4] = AddStaticVehicleEx (597,-1612.3551,748.6299,-5.4733,2.0058,0,1,900); 		// sfpd 5
	sfpd[5] = AddStaticVehicleEx (597,-1608.6771,749.2774,-5.4727,176.4005,0,1,900); 	// sfpd 6
	sfpd[6] = AddStaticVehicleEx (597,-1595.9669,749.0388,-5.4732,180.3730,0,1,900); 	// sfpd 7
	sfpd[7] = AddStaticVehicleEx (597,-1592.2295,748.9126,-5.4712,182.7556,0,1,900); 	// sfpd 8
	sfpd[8] = AddStaticVehicleEx (597,-1580.4562,749.9955,-5.4726,355.0502,0,1,900); 	// sfpd 9
	sfpd[9] = AddStaticVehicleEx (597,-1574.5138,742.9577,-5.4762,270.1100,0,1,900); 	// sfpd 10
	sfpd[10] = AddStaticVehicleEx(597,-1572.8766,738.3235,-5.4734,270.1990,0,1,900); 	// sfpd 11
	sfpd[11] = AddStaticVehicleEx(597,-1574.2340,726.6032,-5.4718,90.6153,0,1,900); 	// sfpd 12
	sfpd[12] = AddStaticVehicleEx(597,-1573.3081,714.1894,-5.4729,269.4365,0,1,900); 	// sfpd 13
	sfpd[13] = AddStaticVehicleEx(597,-1573.1178,705.8439,-5.4776,270.3775,0,1,900); 	// sfpd 14
	sfpd[14] = AddStaticVehicleEx(528,-1620.8623,693.0515,-5.1960,0.1483,0,0,900); 		// fbi truck
	sfpd[15] = AddStaticVehicleEx(528,-1624.6072,693.6392,-5.1981,0.4856,0,0,900); 		// fbi truck
	sfpd[16] = AddStaticVehicleEx(528,-1628.7850,693.8324,-5.1979,359.0162,0,0,900); 	// fbi truck
	sfpd[17] = AddStaticVehicleEx(601,-1633.3557,693.2842,-5.4834,181.1646,1,1,900); 	// swat tank
	sfpd[18] = AddStaticVehicleEx(427,-1600.2168,676.3408,-5.1103,180.5808,0,1,900); 	// enforcer
	sfpd[19] = AddStaticVehicleEx(490,-1595.9580,676.5024,-5.1139,178.4653,0,0,900); 	// fbi rancher
	sfpd[20] = AddStaticVehicleEx(426,-1589.5823,706.0107,-5.4936,269.1462,0,0,900); 	// premier
	sfpd[21] = AddStaticVehicleEx(426,-1589.8179,710.6583,-5.4975,273.0995,0,0,900); 	// premier
	sfpd[22] = AddStaticVehicleEx(523,-1575.4397,693.4268,-5.6714,89.3831,0,0,900); 	// bike
	sfpd[23] = AddStaticVehicleEx(523,-1576.0654,691.9917,-5.6762,82.2769,0,0,900); 	// bike
	sfpd[24] = AddStaticVehicleEx(523,-1576.8134,690.8708,-5.6763,80.3369,0,0,900); 	// bike
	sfpd[25] = AddStaticVehicleEx(523,-1577.4055,689.7529,-5.6715,76.0661,0,0,900); 	// bike
	sfpd[26] = AddStaticVehicleEx(523,-1578.7363,688.7021,-5.6766,70.4354,0,0,900); 	// bike

	// SA-FR
	safr[0] = AddStaticVehicleEx(407,-2021.4797,93.0921,28.2680,273.1411,3,1,900); 		// firetruck
	safr[1] = AddStaticVehicleEx(407,-2022.5248,83.8660,28.3035,269.4807,3,1,900); 		// firetruck
	safr[2] = AddStaticVehicleEx(407,-2021.8317,75.4159,28.3196,272.8612,3,1,900);		// firetruck
	safr[3] = AddStaticVehicleEx(416,-2028.6033,50.2835,29.6724,262.2391,3,3,900); 		// ambu
	safr[4] = AddStaticVehicleEx(416,-2036.6307,51.2457,28.6390,265.2481,3,3,900); 		// ambu
	safr[5] = AddStaticVehicleEx(416,-2044.8951,51.6785,28.5406,268.6777,3,3,900); 		// ambu
	safr[6] = AddStaticVehicleEx(544,-2053.2781,92.5651,28.6196,271.7376,3,1,900); 		// firetruck
	safr[7] = AddStaticVehicleEx(544,-2053.5354,83.6803,28.6341,270.6934,3,1,900); 		// firetruck
	safr[8] = AddStaticVehicleEx(490,-2053.5693,75.1995,28.5193,90.3990,3,3,900); 		// fd fbi rancher
	safr[9] = AddStaticVehicleEx(563,-2089.5229,58.6780,35.4697,126.5743,3,3,900); 		// raindance
	
	// SAN
	san[0] = AddStaticVehicleEx(488,-2473.5317,-603.0758,132.8607,222.3778,2,26,900); 	// san news helicopter
	san[1] = AddStaticVehicleEx(582,-2531.5828,-602.3991,132.6219,180.6031,41,20,900); 	// newsvan
	san[2] = AddStaticVehicleEx(582,-2528.1438,-601.6618,132.6218,0.2276,49,11,900); 	// newsvan (deze kleuren!)
	san[3] = AddStaticVehicleEx(582,-2520.7661,-602.6353,132.6241,179.0571,56,123,900); // newsvan
	san[4] = AddStaticVehicleEx(582,-2516.725,-602.6428,132.6143,181.7848,110,113,900);	// newsvan
	
	
    AddPlayerClass(250,  -1397.9670, -324.8705, 14.1484, 123.1425, 0, 0, 0, 0, 0, 0);
    
    SetGameModeText("Concept");
	return 1;
}

public OnGameModeExit()
{
	return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
	SetPlayerInterior(playerid,14);
	SetPlayerPos(playerid, -1859.8484,24.9062,1061.1436);
	SetPlayerCameraPos(playerid, -1856.8484,28.9062,1061.1436);
	SetPlayerCameraLookAt(playerid, -1851.5903,31.4319,1066.1436);

	GameTextForPlayer(playerid, "~r~log in ~w~or ~r~register ~w~before spawning!", 8000, 5);
	return 1;
}

public OnPlayerRequestSpawn(playerid)
{
	return 1;
}

public OnPlayerConnect(playerid)
{
    AccountInfo[playerid][aLoggedIn] = false;
    AccountInfo[playerid][aIsMuted] = false;
    
    AccountInfo[playerid][aSkin] = 0;
    AccountInfo[playerid][aAdmin] = 0;

    AllowPlayerTeleport(playerid,0);
	return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
 	new string[256];

	if(AccountInfo[playerid][aLoggedIn])
	{
        SavePlayerFile(playerid);

		if (reason == 0)
			format(string, sizeof(string), ">> %s has lost connection to the server", PlayerName(playerid));
		else if (reason == 1)
			format(string, sizeof(string),">> %s has left the server", PlayerName(playerid));

		SendClientMessageToAll(COLOUR_SERVMESSAGE,string);
	}

	for (new i = 0; i < SLOTS; i++)
	{
		if (AccountInfo[i][aSpectating] == playerid)
		{
		    AccountInfo[i][aSpectating] = -1;
		    TogglePlayerSpectating(i, 0);
		    SendClientMessage(i, COLOUR_SERVMESSAGE, ">> You stopped spectating");
		}
	}
	
	return 1;
}

public OnPlayerSpawn(playerid)
{
	if (!AccountInfo[playerid][aLoggedIn])
	{
	    SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Please register or log in before spawning next time");
	    Kick(playerid);

	    return 1;
	}
	
	if (AccountInfo[playerid][aSkin] == 0)
		AccountInfo[playerid][aSkin] = STANDARD_PLAYER_SKIN;
		
	//SetPlayerSkin(playerid, AccountInfo[playerid][aSkin]);
	
	SetPlayerInterior(playerid, 0);
	SetPlayerPos(playerid, -1397.9670, -324.8705, 14.1484);
	SetPlayerFacingAngle(playerid, 123.1);
	SetCameraBehindPlayer(playerid);
	
	return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
	return 1;
}

public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
{
	// spectating
	for (new i = 0; i < SLOTS; i++)
		if (AccountInfo[i][aSpectating] == playerid)
		{
		    SetPlayerInterior(i, newinteriorid);
		    SetPlayerVirtualWorld(i, GetPlayerVirtualWorld(playerid));
		}

	return 1;
}

public OnVehicleSpawn(vehicleid)
{
	return 1;
}

public OnVehicleDeath(vehicleid, killerid)
{
	return 1;
}

public OnPlayerText(playerid, text[])
{
	if (!AccountInfo[playerid][aLoggedIn])
	{
	    SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> Log in first");
	    return 0;
	}
	if (AccountInfo[playerid][aIsMuted])
	{
	    SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> You've been muted by an admin");
	    return 0;
	}

	OnClientLocalChat(playerid,text);
	return 0;
}

public OnPlayerPrivmsg(playerid, recieverid, text[])
{
	return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    new command[32], params[96], string[128], tmp[128], idx;

    if (strfind(cmdtext, " ", false) != -1)
    {
        strmid(command, cmdtext, 0, strfind(cmdtext, " ", false));
        strmid(params, cmdtext, strfind(cmdtext, " ", false), strlen(cmdtext));
    }
    else
        strmid(command, cmdtext, 0, strlen(cmdtext));

	// seperated command from params - if they are there
	
	// first the commands you can enter without logging in
	if (strcmp(command, "/register", true) == 0)
	{
	    format(string, sizeof(string), "concept/%s.cpf", PlayerName(playerid));
		if (fexist(string))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> your username is already registered");

		if (strcmp(params,cmdtext,false) == 0)
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /register [password]");

		if (strlen(params) > 16)
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> your password length must not exceed 16 characters.");
		    
		new File: file = fopen(string, io_readwrite);
		format(string, sizeof(string), "%s\r\n", params);
		fwrite(file, string);
		fclose(file);

		AccountInfo[playerid][aSkin] = STANDARD_PLAYER_SKIN;
        SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> your account has been created.");
        SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> please log in before spawning.");
		return 1;
	}
	if (strcmp(command, "/login", true) == 0)
	{
	    new string2[256], ip[16];
	    GetPlayerIp(playerid,ip,16);

	    format(string, sizeof(string), "concept/%s.cpf", PlayerName(playerid));
		if (!fexist(string))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> your username is not registered");

        if (AccountInfo[playerid][aLoggedIn])
            return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> you've logged in already");

		if (strcmp(params,cmdtext,false) == 0)
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /login [password]");

		new File:file = fopen(string,io_read);
		if (!file)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> an unknown error occured.");

		fread(file,tmp);
		fclose(file);

		if (strfind(tmp, "\r\n", true) > -1)
			strdel(tmp, strfind(tmp, "\r\n", true), strlen(tmp));

		strmid(AccountInfo[playerid][aPassword], tmp, 0, 256, 255);

		if (strcmp (tmp, params, true, strlen(tmp)) != 0 || strlen(params) != strlen(tmp))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> incorrect password");

        SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Thank you for logging in.");

		format(string, sizeof(string), ">> %s has joined the server", PlayerName(playerid, true));
		format(string2, sizeof(string2), ">> %s has joined the server [ip: %s]", PlayerName(playerid, true),ip);

		for (new i = 0; i < SLOTS; i++)
		    if (AccountInfo[i][aAdmin] <= 0)
				SendClientMessage(i,COLOUR_SERVMESSAGE,string);
		    else
				SendClientMessage(i,COLOUR_SERVMESSAGE,string2);

		OnPlayerLogin(playerid);
		return 1;
	}
	
	// ------------------------------------------------------------------
	// Everything beneath this point cannot be accessed unless someone is logged in!
	// -------------------------------------------------------------------
	if (!AccountInfo[playerid][aLoggedIn])
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> Log in first");
	if (AccountInfo[playerid][aIsMuted])
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> You've been muted by an admin");

	// ------------------------------------------------------------------
	// Everything beneath this point cannot be accessed unless someone is logged in!
	// -------------------------------------------------------------------

	// chat commands
	if (strcmp(command, "/adm", true) == 0 || strcmp(command, "/report", true) == 0)
		return SendClientMessageToAdmin(playerid,params);

	if (strcmp(command, "/meg", true) == 0)
	{
	    format(string,sizeof(string),"<G> %s %s",PlayerName(playerid, true), params);
		return SendClientActionToAll(string);
	}
	if (strcmp(command, "/me", true) == 0)
	{
	    format(string,sizeof(string),"<R> %s %s",PlayerName(playerid, true), params);
		return SendClientActionToRange(10,playerid,string);
	}
	if (strcmp(command, "//", true) == 0 || strcmp(command, "/all", true) == 0)
	    return SendClientGlobalChat(playerid, params);

	if (strcmp(command, "/s", true) == 0  || strcmp(command, "/shout", true) == 0)
	    return SendClientRadiusChat(playerid, params, 40);

	if (strcmp(command, "/w", true) == 0  || strcmp(command, "/whisper", true) == 0)
	    return SendClientRadiusChat(playerid, params, 5);
	    
	// admin commands
	if (strcmp(command, "/admins", true) == 0) // not necessarily an admin command, but it kinda fits here
	{
	    new admins[4][96];
	    new adminranks[4][32] = { { "junior admins:" }, { "senior admins:" }, { "super admins:" }, {"staff admins:" } };

		for (new i = 0; i < SLOTS; i++)
	    {
			if (!IsPlayerConnected(i))
				continue;
				
            if (AccountInfo[i][aAdmin] > 0)
                format(admins[ (AccountInfo[i][aAdmin]-1) ], 96, "%s, %s", admins[ (AccountInfo[i][aAdmin]-1) ], PlayerName(i, true));
		}
		
		for (new i = 0; i < sizeof(admins); i++)
		{
			if (strlen(admins[i]) > 0)
			    strdel(admins[i], 0, 1);
			else
			    format(admins[i], 96, "none");
			    
			format(string, sizeof(string), "%s %s", adminranks[i], admins[i]);
			SendClientMessage(playerid, 0xFFFFFF00, string);
		}
		
	    return 1;
	}
	
	if (strcmp(command, "/kick", true) == 0)
	{
	    new reason[128],pid;
	    idx = strfind(params," ",false);
	    // identify the reason & playerid
	    strmid(reason, params, 0, idx);
		pid = strval(reason);

	    strmid(reason, params, idx + 1, 256);

	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (AccountInfo[playerid][aAdmin] < AccountInfo[pid][aAdmin])
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> You cannot kick admins that have a higher level than you");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(reason))
		    format(reason, sizeof(reason), "%s", PlayerName(pid,false));

		format(string, sizeof(string), ">> %s %s kicked %s from the server (%s)", OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true), PlayerName(pid,true), reason);
		SendClientMessageToAll(COLOUR_ADM, string);
		Kick(pid);
		
		return 1;
	}
	if (strcmp(command, "/ban", true) == 0)
	{
	    new reason[128],pid;
	    idx = strfind(params," ",false);
	    // identify the reason & playerid
	    strmid(reason, params, 0, idx);
		pid = strval(reason);

	    strmid(reason, params, idx + 1, 256);

	    if (AccountInfo[playerid][aAdmin] <= 1)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command level two, keep your dirty hands off it!");

		if (AccountInfo[playerid][aAdmin] < AccountInfo[pid][aAdmin])
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> You cannot ban admins that have a higher level than you");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(reason))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /ban [playerid] [reason]");

		format(string, sizeof(string), ">> %s %s banned %s from the server (%s)", OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true), PlayerName(pid,true), reason);
		SendClientMessageToAll(COLOUR_ADM, string);
		Ban(pid);
		return 1;
	}

	if (strcmp(command, "/freeze", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /freeze [playerid]");

		format(string, sizeof(string), ">> %s was frozen by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
		TogglePlayerControllable(pid,0);

		return 1;
	}
	if (strcmp(command, "/unfreeze", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /unfreeze [playerid]");

		format(string, sizeof(string), ">> %s was unfrozen by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
		TogglePlayerControllable(pid,1);

		return 1;
	}
	if (strcmp(command, "/mute", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /mute [playerid]");

		format(string, sizeof(string), ">> %s was muted by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
		AccountInfo[pid][aIsMuted] = true;

	    return 1;
	}

	if (strcmp(command, "/voice", true) == 0 || strcmp(command, "/unmute", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /voice [playerid]");

		format(string, sizeof(string), ">> %s was unmuted by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
		AccountInfo[pid][aIsMuted] = false;

	    return 1;
	}

	if (strcmp(command, "/incar", true) == 0 || strcmp(command, "/gtic", true) == 0)
	{
		new pid, seat;

		tmp = strtok(params, idx);
		if (!strlen(tmp))
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /incar [playerid] [seat]");
		else
			pid = strval(tmp);

		tmp = strtok(params, idx);
		if (!strlen(tmp))
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /incar [playerid] [seat]");
		else
			seat = strval(tmp);

		if (AccountInfo[playerid][aAdmin] < 1)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> You're not an admin");

		if (!IsPlayerConnected(pid) || pid == INVALID_PLAYER_ID)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player isn't connected");
		if (!IsPlayerInAnyVehicle(pid))
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player isn't in a vehicle");

		SetPlayerInterior(playerid, 0);
		PutPlayerInVehicle(playerid, GetPlayerVehicleID(pid), seat);
		return 1;
	}

	if (strcmp(command, "/p2p", true) == 0)
	{
		new player1, player2, Float: px, Float: py, Float: pz, vehid;

		tmp = strtok(params, idx);
		if (!strlen(tmp))
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /p2p [playerid 1] [playerid 2]");
		else
			player1 = strval(tmp);

		tmp = strtok(params, idx);
		if (!strlen(tmp))
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /p2p [playerid 1] [playerid 2]");
		else
			player2 = strval(tmp);

		if (AccountInfo[playerid][aAdmin] < 1)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> You're not an admin");

		if (!IsPlayerConnected(player1) || player1 == INVALID_PLAYER_ID)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Player 1 isn't connected");
		if (!IsPlayerConnected(player2) || player2 == INVALID_PLAYER_ID)
			return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Player 2 isn't connected");


		GetPlayerPos(player2, px, py, pz);
		SetPlayerInterior(player1, GetPlayerInterior(player2));
		SetPlayerVirtualWorld(player1, GetPlayerVirtualWorld(player2));
		if (IsPlayerInAnyVehicle(player1) && GetPlayerState(player1) == PLAYER_STATE_DRIVER && GetPlayerInterior(player2) == 0 && GetPlayerVirtualWorld(player2) == 0)
		{
		    vehid = GetPlayerVehicleID(player1);
		    SetVehiclePos(vehid, px, py, pz);
		    PutPlayerInVehicle(player1, vehid, 0);
		}
		else
		{
		    SetPlayerPos(player1, px, py, pz);
		}
		return 1;
		#pragma unused vehid
	}

	if (strcmp(command, "/meto", true) == 0 || strcmp(command, "/goto", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /meto [playerid]");

		new Float:x, Float:y, Float:z;
		if (!IsPlayerInAnyVehicle(pid))
			GetPlayerPos(pid,x,y,z);
		else
		    GetVehiclePos( GetPlayerVehicleID(pid), x, y, z);

		if (!IsPlayerInAnyVehicle(playerid))
			SetPlayerPos(playerid, (x + 0.1), (y + 0.1), z);
		else
		    SetVehiclePos( GetPlayerVehicleID(playerid), x, y, z);

		SetPlayerInterior(playerid, GetPlayerInterior(pid));
		SetPlayerVirtualWorld(playerid, GetPlayerVirtualWorld(pid));
	    return 1;
	}

	if (strcmp(command, "/tome", true) == 0 || strcmp(command, "/get", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /tome [playerid]");

		new Float:x, Float:y, Float:z;
		if (!IsPlayerInAnyVehicle(playerid))
			GetPlayerPos(playerid,x,y,z);
		else
		    GetVehiclePos( GetPlayerVehicleID(playerid), x, y, z);

		if (!IsPlayerInAnyVehicle(pid))
			SetPlayerPos(pid, (x + 0.1), (y + 0.1), z);
		else
		    SetVehiclePos( GetPlayerVehicleID(pid), x, y, z);

		SetPlayerInterior(pid, GetPlayerInterior(playerid));
		SetPlayerVirtualWorld(pid, GetPlayerVirtualWorld(playerid));
	    return 1;
	}

	if (strcmp(command, "/spectate", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /spectate [playerid]");

		if (AccountInfo[playerid][aSpectating] != -1)
		{
		    AccountInfo[playerid][aSpectating] = -1;
		    TogglePlayerSpectating(playerid, 0);
		    SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> You stopped spectating");
		    return 1;
		}

		AccountInfo[playerid][aSpectating] = pid;
		TogglePlayerSpectating(playerid, 1);
		SetPlayerInterior(playerid, GetPlayerInterior(pid));
		SetPlayerVirtualWorld(playerid, GetPlayerVirtualWorld(pid));

		if (IsPlayerInAnyVehicle(pid))
			PlayerSpectateVehicle(playerid, GetPlayerVehicleID(pid));
		else
			PlayerSpectatePlayer(playerid, pid);

		format(string, sizeof(string), ">> You are now spectating %s", PlayerName(pid,true));
		SendClientMessage(playerid, COLOUR_SERVMESSAGE, string);

		if (AccountInfo[pid][aAdmin] > 1) // so people dont sneak up un me D:
		{
			format(string, sizeof(string), ">> You are now being spectated by %s", PlayerName(playerid,true));
			SendClientMessage(pid, COLOUR_SERVMESSAGE, string);
		}
	    return 1;
	}

	if (strcmp(command, "/slap", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /slap [playerid]");

		new Float:x, Float:y, Float:z, Float:health;
		if (IsPlayerInAnyVehicle(pid))
		    GetVehiclePos(GetPlayerVehicleID(pid), x, y, z);
		else
		    GetPlayerPos(pid, x, y, z);

		GetPlayerHealth(pid,health);

		if(health > 100)
		    health = 100;

		SetPlayerHealth(pid,health-5);
		SetPlayerPos(pid, x, y, z + 10);

		format(string, sizeof(string), ">> %s was slapped by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);

		return 1;
	}

	if (strcmp(command, "/mslap", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 1)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration level 2 command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /mslap [playerid]");

		new Float:x, Float:y, Float:z;
		GetPlayerPos(pid,x,y,z);
		SetPlayerPos(pid,x,y,z+1000);

		format(string, sizeof(string), ">> %s was monster slapped by %s %s", PlayerName(pid,true), OrgRankNames[0][ AccountInfo[playerid][aAdmin] ], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
		return 1;
	}

	if (strcmp(command, "/explode", true) == 0)
	{
	    new pid = strval(params);
	    if (AccountInfo[playerid][aAdmin] <= 1)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration level 2 command, keep your dirty hands off it!");

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player is not connected");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /explode [playerid]");

		new Float:x, Float:y, Float:z;
		if (IsPlayerInAnyVehicle(pid))
		    GetVehiclePos(GetPlayerVehicleID(pid), x, y, z);
		else
		    GetPlayerPos(pid, x, y, z);

		CreateExplosion(x, y, z, 6, 20);

		format(string, sizeof(string), ">> %s was exploded by %s %s", PlayerName(pid,true), OrgRankNames[0][AccountInfo[playerid][aAdmin]], PlayerName(playerid,true));
		SendClientMessageToAll(COLOUR_ADM, string);
	    return 1;
	}

	if (strcmp(command, "/ann", true) == 0 || strcmp(command, "/announce", true) == 0)
	{
	    if (AccountInfo[playerid][aAdmin] <= 0)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration command, keep your dirty hands off it!");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /ann(ounce) [text]");

		GameTextForAll(params,3000,5);
	    return 1;
	}

	if (strcmp(command, "/adminpm", true) == 0 || strcmp(command, "/apm", true) == 0)
	{
	    new text[256],pid;

	    if (AccountInfo[playerid][aAdmin] <= 1)
	     	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> Administration level 2 command, keep your dirty hands off it!");

		if (!strlen(params))
		    return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /a(dmin)pm [playerid] [text]");

	    idx = strfind(params," ",false);

	    strmid(string, params, 0, idx);
	    strmid(text, params, idx + 1, 256);
		pid = strval(string);

		if (!IsPlayerConnected(pid))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> That player isn't connected");
		if (!strlen(text))
		 	return SendClientMessage(playerid, COLOUR_SERVMESSAGE, ">> correct usage: /a(dmin)pm [playerid] [text]");

		format(string, sizeof(string), "~r~pm from %s %s:~n~~w~ %s", OrgRankNames[0][ AccountInfo[playerid][aAdmin] ], PlayerName(playerid, true), text);
		GameTextForPlayer(pid, string, 3000, 5);
	    return 1;
	}
	
    return SendClientMessage(playerid, 0xFFFFFF00, "no such command");
}

public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
	return 1;
}

public OnPlayerExitVehicle(playerid, vehicleid)
{
	return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
	// spectating
	if (newstate == PLAYER_STATE_DRIVER || newstate == PLAYER_STATE_PASSENGER)
	    for (new i = 0; i < SLOTS; i++)
	        if (AccountInfo[i][aSpectating] == playerid)
	            PlayerSpectateVehicle(i, GetPlayerVehicleID(playerid));

	if (oldstate == PLAYER_STATE_DRIVER || oldstate == PLAYER_STATE_PASSENGER)
	    for (new i = 0; i < SLOTS; i++)
	        if (AccountInfo[i][aSpectating] == playerid)
	            PlayerSpectatePlayer(i, playerid);
	            
	return 1;
}

public OnPlayerEnterCheckpoint(playerid)
{
	return 1;
}

public OnPlayerLeaveCheckpoint(playerid)
{
	return 1;
}

public OnPlayerPickUpPickup(playerid, pickupid)
{
	return 1;
}

public SavePlayerFile(playerid)
{
	if(!IsPlayerConnected(playerid) || !AccountInfo[playerid][aLoggedIn])
	    return 1;
	else
	    SetTimerEx("UpdatePlayerFile",60000,0,"i",playerid);

	new params[128];

    format(params, sizeof(params), "concept/%s.cpf", PlayerName(playerid));
	if (!fexist(params))
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> An unknown error occured, contact an admin with error code SAV-01");

	new File:file = fopen(params,io_write);
	if (!file)
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> An unknown error occured, contact an admin with error code SAV-02");

	format(params, sizeof(params), "%s\r\n",AccountInfo[playerid][aPassword]);
    fwrite(file,params);
	format(params, sizeof(params), "%d aSkin\r\n",AccountInfo[playerid][aSkin]);
    fwrite(file,params);
 	format(params, sizeof(params), "%d aAdmin\r\n",AccountInfo[playerid][aAdmin]);
    fwrite(file,params);
    
    fclose(file);
    return 1;
}

// custom callbacks
stock OnPlayerLogin(playerid)
{
    new params[512],filename[32];

    format(filename, sizeof(filename), "concept/%s.cpf", PlayerName(playerid));
	if (!fexist(filename))
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> Your name has not been registered yet!");

	new File:file = fopen(filename,io_read);
	if (!file)
	    return SendClientMessage(playerid,COLOUR_SERVMESSAGE, ">> An unknown error occured, contact an admin with error code LOG-02");

	AccountInfo[playerid][aLoggedIn] = true;
	SetTimerEx("SavePlayerFile", 60000, 0, "i", playerid);
	
	fread(file,params); // omit password
	
	fread(file,params);
	AccountInfo[playerid][aSkin] = strval(params);
	fread(file,params);
	AccountInfo[playerid][aAdmin] = strval(params);
	
	fclose(file);
	
	SetPlayerInterior(playerid, 0);
	SpawnPlayer(playerid);
	return 1;
}
stock OnClientLocalChat(playerid, string[])
{
	new message[256];

	if (string[ (strlen(string) -1) ] == '!')
	{
	    if (SendClientRadiusChat(playerid, string, 40) == 0)
     		SendClientMessage(playerid, 0xF2F2F2FF, "You can shout however much you want, noone can here you!");

		return 1;
	}
	if (strcmp(string, ":(", false) == 0)
	{
	    format(message, sizeof(message), "<> %s is sad", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":)", false) == 0)
	{
	    format(message, sizeof(message), "<> %s is happy", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ">.>", false) == 0 || strcmp(string, "<.<", false) == 0 || strcmp(string, "D:", false) == 0 || strcmp(string, ":@", false) == 0)
	{
	    format(message, sizeof(message), "<> %s is not amused", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":D", false) == 0 || strcmp(string, ":P", false) == 0)
	{
	    format(message, sizeof(message), "<> %s laughs", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":S", false) == 0)
	{
	    format(message, sizeof(message), "<> %s looks confused", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":'(", false) == 0)
	{
	    format(message, sizeof(message), "<> %s cries", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":$", false) == 0)
	{
	    format(message, sizeof(message), "<> %s shuts up", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":O", true) == 0)
	{
	    format(message, sizeof(message), "<> %s seems confused", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}
	if (strcmp(string, ":|", true) == 0 || strcmp(string, ":\\", false) == 0 || strcmp(string, ":/", false) == 0)
	{
	    format(message, sizeof(message), "<> %s seems vexed", PlayerName(playerid,true));
	    return SendClientActionToRange(20, playerid, message);
	}

	if (string[ (strlen(string) -1) ] == '?')
	    format(message, 256, "%s asks: %s",PlayerName(playerid,true),string);
	else
		format(message, 256, "%s says: %s",PlayerName(playerid,true),string);

	if (SendClientRangeMessage(playerid, 20, message, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF) == 0)
	    return SendClientMessage(playerid, 0xF2F2F2FF, "Noone bothered to listen to what you were saying");

	return 1;
}

stock SendClientRadiusChat(playerid, string[], radius)
{
	new message[256];
	format(message, 256, "%s says: %s",PlayerName(playerid,true),string);

	if (radius == 5)
		format(message, 256, "%s whispers: %s",PlayerName(playerid,true),string);
	if (radius == 40)
	    format(message, 256, "%s shouts: %s",PlayerName(playerid,true),string);

    return SendClientRangeMessage(playerid, radius, message, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF, 0xF2F2F2FF);
}

stock SendClientActionToAll(string[])
{
	return SendClientMessageToAll(COLOUR_PLAYERACTION, string);
}

stock SendClientActionToClient(recieverid, string[])
{
	return SendClientMessage(recieverid, COLOUR_PLAYERACTION, string);
}

stock SendClientActionToRange(radi,playerid,string[])
{
	new Float:posx, Float:posy, Float:posz;
	new Float:oldposx, Float:oldposy, Float:oldposz;
	new Float:tempposx, Float:tempposy, Float:tempposz;
	GetPlayerPos(playerid, oldposx, oldposy, oldposz);

	for (new i = 0; i <= SLOTS; i++)
		if (IsPlayerConnected(i) && GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
		{
				GetPlayerPos(i, posx, posy, posz);
				tempposx = (oldposx - posx);
				tempposy = (oldposy - posy);
				tempposz = (oldposz - posz);

				if (((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi)))
					 SendClientActionToClient(i, string);
		}
	return 1;
}

stock SendClientRangeMessage(playerid, Float:radi, string [], col1, col2, col3, col4, col5)
{
	new Float:posx, Float:posy, Float:posz;
	new Float:oldposx, Float:oldposy, Float:oldposz;
	new Float:tempposx, Float:tempposy, Float:tempposz;
	GetPlayerPos(playerid, oldposx, oldposy, oldposz);

	new bool: sent = false;

	for (new i = 0; i <= SLOTS; i++)
		if (IsPlayerConnected(i) && GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
		{
				GetPlayerPos(i, posx, posy, posz);
				tempposx = (oldposx - posx);
				tempposy = (oldposy - posy);
				tempposz = (oldposz - posz);

                if (((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi)) && playerid != i)
                    sent = true;

				if (((tempposx < radi / 16) && (tempposx > -radi / 16)) && ((tempposy < radi / 16) && (tempposy > -radi / 16)) && ((tempposz < radi / 16) && (tempposz > -radi / 16)))
					SendClientMessage(i, col1, string );
				else if (((tempposx < radi / 8) && (tempposx > -radi / 8)) && ((tempposy < radi / 8) && (tempposy > -radi / 8)) && ((tempposz < radi / 8) && (tempposz > -radi / 8)))
					SendClientMessage(i, col2, string );
				else if (((tempposx < radi / 4) && (tempposx > -radi / 4)) && ((tempposy < radi / 4) && (tempposy > -radi / 4)) && ((tempposz < radi / 4) && (tempposz > -radi / 4)))
					SendClientMessage(i, col3, string );
				else if (((tempposx < radi / 2) && (tempposx > -radi / 2)) && ((tempposy < radi / 2) && (tempposy > -radi / 2)) && ((tempposz < radi / 2) && (tempposz > -radi / 2)))
					SendClientMessage(i, col4, string );
				else if (((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi)))
					SendClientMessage(i, col5, string );
		}

	if (!sent) // smexy!
	    return 0;

	return 1;
}

stock SendClientGlobalChat(playerid, string[])
{
	new message[256];
	format(message, 256, "%s: %s",PlayerName(playerid,true), string);

	SendClientMessageToAll(0xFFBD7AFF, message);

	return 1;
}

stock SendClientMessageToAdmin(playerid, string[])
{
    new message[256];
    new AdmLevels[4][0] = {{ "REPORT:" }, { "Mod" }, { "Admin" }, { "Script Admin" }};
    format(message, sizeof(message), ">> %s %s: %s",AdmLevels[AccountInfo[playerid][aAdmin]], PlayerName(playerid,true), string);
    for(new i; i < SLOTS; i++)
        if (AccountInfo[i][aAdmin] >= 1)
			SendClientMessage(i, COLOUR_ADM, message);
	return 1;
}

stock PlayerName(playerid, truncate = false)
{
	new name[32];
	GetPlayerName(playerid,name,32);

	if(truncate)
	{
		new idx = strfind(name,"_",true);
		if(idx > -1)
			name[idx] = ' ';

	    idx = strfind(name,"[",true);
	    new idx2 = strfind(name,"]",true);
	    if (idx2 > idx && idx2 < strlen(name))
	        strdel(name,idx,idx2+1);
	}

	return name;
}

stock strtok( const string[], &index = 0, const seperator[] = " " )
{
	new index2, result[ 30 ];
	index2 =  strfind(string, seperator, false, index);

	if(index2 == -1)
	{
		if(strlen(string) > index)
		{
			strmid(result, string, index, strlen(string), 30);
			index = strlen(string);
		}
		return result; // This string is empty, probably, if index came to an end
	}

	if(index2 > (index + 29))
	{
		index2 = index + 29;
		strmid(result, string, index, index2, 30);
		index = index2;
		return result;
	}

	strmid(result, string, index, index2, 30);
	index = index2 + 1;
	return result;
}
